home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 051-075 / 068 / mg1b / match.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  5KB  |  222 lines

  1. /*
  2.  * Name:    MicroEMACS
  3.  *         Limited parenthesis matching routines
  4.  * Version:    Gnu30
  5.  * Last edit:    13-Jul-86
  6.  * Created:    19-May-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  7.  *
  8.  * The hacks in this file implement automatic matching
  9.  * of (), [], {}, and other characters.  It would be
  10.  * better to have a full-blown syntax table, but there's
  11.  * enough overhead in the editor as it is.
  12.  *
  13.  * Since I often edit Scribe code, I've made it possible to
  14.  * blink arbitrary characters -- just bind delimiter characters
  15.  * to "blink-matching-paren-hack"
  16.  */
  17. #include    "def.h"
  18.  
  19. static int balance();
  20. static displaymatch();
  21.  
  22. /* Balance table. When balance() encounters a character
  23.  * that is to be matched, it first searches this table
  24.  * for a balancing left-side character.  If the character
  25.  * is not in the table, the character is balanced by itself.
  26.  * This is to allow delimiters in Scribe documents to be matched.
  27.  */    
  28.  
  29. static struct balance {
  30.     char left, right;
  31. } bal[] = {
  32.     { '(', ')' },
  33.     { '[', ']' },
  34.     { '{', '}' },
  35.     { '<', '>' },
  36.     { '\0','\0'}
  37. };
  38.  
  39. /*
  40.  * Fake the GNU "blink-matching-paren" variable.
  41.  * If the argument exists, nonzero means show,
  42.  * zero means don't.  If it doesn't exist,
  43.  * pretend it's nonzero.
  44.  */
  45.  
  46. blinkparen(f, n, k)
  47. {
  48.     register char    *command;
  49.     register SYMBOL    *sp;
  50.  
  51.     if (f == FALSE)
  52.         n = 1;
  53.     command = (n == 0) ? "self-insert-command" :
  54.                  "blink-matching-paren-hack";
  55.     if ((sp=symlookup(command)) == NULL) {
  56.         ewprintf("blinkparen: no binding for %s",command);
  57.         return (FALSE);
  58.     }
  59.     binding[(KEY) ')'] = sp;        /* rebind paren        */
  60.     return (TRUE);    
  61. }
  62.  
  63. /*
  64.  * Self-insert character, then show matching character,
  65.  * if any.  Bound to "blink-matching-paren-command".
  66.  */
  67.  
  68. showmatch(f, n, k)
  69. {
  70.     register int  i, s;
  71.  
  72.     if (k == KRANDOM)
  73.         return(FALSE);
  74.     for (i = 0; i < n; i++) {
  75.         if ((s = selfinsert(f, 1, k)) != TRUE)
  76.             return(s);
  77.         if (balance(k) != TRUE)    /* unbalanced -- warn user */
  78.             ttbeep();
  79.     }
  80.     return (TRUE);
  81. }
  82.  
  83. /*
  84.  * Search for and display a matching character.
  85.  *
  86.  * This routine does the real work of searching backward
  87.  * for a balancing character.  If such a balancing character
  88.  * is found, it uses displaymatch() to display the match.
  89.  */
  90.  
  91. static balance(k)
  92. int k;
  93. {
  94.     register LINE    *clp;
  95.     register int    cbo;
  96.     int    c;
  97.     int    i;
  98.     int    rbal, lbal;
  99.     int    depth;
  100.  
  101.     rbal = k & KCHAR;
  102.     if ((k&KCTRL)!=0 && rbal>='@' && rbal<='_') /* ASCII-ify.    */
  103.         rbal -= '@';
  104.  
  105.     /* See if there is a matching character -- default to the same */
  106.  
  107.     lbal = rbal;
  108.     for (i = 0; bal[i].right != '\0'; i++)
  109.         if (bal[i].right == rbal) {
  110.             lbal = bal[i].left;
  111.             break;
  112.         }
  113.  
  114.     /* Move behind the inserted character.  We are always guaranteed    */
  115.     /* that there is at least one character on the line, since one was  */
  116.     /* just self-inserted by blinkparen.                    */
  117.  
  118.     clp = curwp->w_dotp;
  119.     cbo = curwp->w_doto - 1;
  120.  
  121.     depth = 0;            /* init nesting depth        */
  122.  
  123.     for (;;) {
  124.         if (cbo == 0) {            /* beginning of line    */
  125.             clp = lback(clp);
  126.             if (clp == curbp->b_linep)
  127.                 return (FALSE);
  128.             cbo = llength(clp)+1;
  129.         }
  130.         if (--cbo == llength(clp))    /* end of line        */
  131.             c = '\n';
  132.         else
  133.             c = lgetc(clp,cbo);    /* somewhere in middle    */
  134.  
  135.         /* Check for a matching character.  If still in a nested */
  136.         /* level, pop out of it and continue search.  This check */
  137.         /* is done before the nesting check so single-character     */
  138.         /* matches will work too.                 */
  139.         if (c == lbal) {
  140.             if (depth == 0) {
  141.                 displaymatch(clp,cbo);
  142.                 return (TRUE);
  143.             }
  144.             else
  145.                 depth--;
  146.         }
  147.         /* Check for another level of nesting.  */
  148.         if (c == rbal)
  149.             depth++;
  150.     }
  151.     /*NOTREACHED*/
  152. }
  153.  
  154.  
  155. /*
  156.  * Display matching character.
  157.  * Matching characters that are not in the current window
  158.  * are displayed in the echo line. If in the current
  159.  * window, move dot to the matching character,
  160.  * sit there a while, then move back.
  161.  */
  162.  
  163. static displaymatch(clp, cbo)
  164. register LINE *clp;
  165. register int  cbo;
  166. {
  167.     register LINE    *tlp;
  168.     register int    tbo;
  169.     register int    cp;
  170.     register int    bufo;
  171.     register int    c;
  172.     int        inwindow;
  173.     char         buf[NLINE];
  174.  
  175.     /* Figure out if matching char is in current window by    */
  176.     /* searching from the top of the window to dot.        */
  177.  
  178.     inwindow = FALSE;
  179.     for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
  180.         if (tlp == clp)
  181.             inwindow = TRUE;
  182.  
  183.     if (inwindow == TRUE) {
  184.         tlp = curwp->w_dotp;    /* save current position */
  185.         tbo = curwp->w_doto;
  186.  
  187.         curwp->w_dotp  = clp;    /* move to new position */
  188.         curwp->w_doto  = cbo;
  189.         curwp->w_flag |= WFMOVE;
  190.  
  191.         update();        /* show match */
  192.         sleep(1);        /* wait a bit */
  193.  
  194.         curwp->w_dotp   = tlp;    /* return to old position */
  195.         curwp->w_doto   = tbo;
  196.         curwp->w_flag  |= WFMOVE;
  197.         update();
  198.     }
  199.     else {    /* match not in this window so display line in echo area */
  200.         bufo = 0;
  201.         for (cp = 0; cp < llength(clp); cp++) {    /* expand tabs    */
  202.             c = lgetc(clp,cp);
  203.                         if (
  204. #ifdef    NOTAB
  205.                 (mode&MNOTAB) ||
  206. #endif
  207.                 c != '\t')
  208.                     if(ISCTRL(c)) {
  209.                     buf[bufo++] = '^';
  210.                     buf[bufo++] = c ^ 0x40;
  211.                 } else buf[bufo++] = c;
  212.             else
  213.                 do {
  214.                     buf[bufo++] = ' ';
  215.                 } while (bufo & 7);
  216.         }
  217.         buf[bufo++] = '\0';
  218.         ewprintf("Matches %s",buf);
  219.     }
  220.     return (TRUE);
  221. }
  222.